package de.fmaul.dicheck.runner;

import de.fmaul.dicheck.assertions.Assertion;
import de.fmaul.dicheck.model.DataRow;
import de.fmaul.dicheck.model.DataTable;
import de.fmaul.dicheck.model.Property;
import de.fmaul.dicheck.model.TestCase;
import de.fmaul.dicheck.model.TestContainer;

public abstract class AbstractTestRunner implements TestRunner {

    public final TestRunnerResult runTests(final TestContainer tests) {

        final TestRunnerResult results = new TestRunnerResult();
        runAllTestsInContainer(tests, results);
        postAllTestsRun();

        return results;

    }

    private final void runAllTestsInContainer(final TestContainer tests,
            final TestRunnerResult results) {

        int delay = Property.getInt(tests.getProperties(), Property.DELAY);

        for (final TestCase testCase : tests.getTestCases()) {
            TestResult testResult = runTestCase(testCase);
            results.putResult(testCase, testResult);

            if (delay > 0) {
                try {
                    Thread.sleep(delay);
                } catch (InterruptedException e) {
                    // ignore the interruption
                }
            }
        }

        for (final TestContainer container : tests.getSubContainers()) {
            runAllTestsInContainer(container, results);
        }

    }

    abstract protected TestResult runTestCase(final TestCase testCase);

    abstract void postAllTestsRun();

    final protected void checkTableTestAssertions(final TestCase testCase,
            final TestResult testResult, final DataTable dt) {
        for (final Assertion a : testCase.getAssertions()) {
            a.checkMetaData(testCase, testResult, dt.getMetaData());
        }
    }

    final protected void checkPostTestAssertions(final TestCase testCase,
            final TestResult testResult) {
        for (final Assertion a : testCase.getAssertions()) {
            a.checkDataSet(testCase, testResult, testResult.getDataSet());
        }

        for (final Assertion a : testCase.getAssertions()) {
            a.postTest(testCase, testResult);
        }
    }

    final protected void checkRowTestAssertions(final TestCase testCase,
            final TestResult testResult, final DataRow row) {
        // test all assertions associated with this test
        for (final Assertion a : testCase.getAssertions()) {
            a.checkRow(testCase, testResult, row);
        }
    }

    final protected void checkPreTestAssertions(final TestCase testCase,
            final TestResult testResult) {
        for (final Assertion a : testCase.getAssertions()) {
            a.preTest(testCase, testResult);
        }
    }

}